home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / vim / src / winnt.c < prev   
C/C++ Source or Header  |  1995-03-09  |  31KB  |  1,198 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMproved
  4.  *
  5.  */
  6.  
  7. /*
  8.  * winnt.c
  9.  *
  10.  * Windows NT system-dependent routines.
  11.  * A reasonable approximation of the amiga dependent code.
  12.  * Portions lifted from SDK samples, from the MSDOS dependent code,
  13.  * and from NetHack 3.1.3.
  14.  *
  15.  * rogerk@wonderware.com
  16.  */
  17.  
  18. #include <io.h>
  19. #include "vim.h"
  20. #include "globals.h"
  21. #include "param.h"
  22. #include "proto.h"
  23. #include <fcntl.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <errno.h>
  27. #include <stdlib.h>
  28. #include <windows.h>
  29. #include <wincon.h>
  30.  
  31. static int WaitForChar __ARGS((int));
  32. static int cbrk_handler __ARGS(());
  33.  
  34. /* Win32 Console handles for input and output */
  35. HANDLE          hConIn;
  36. HANDLE          hConOut;
  37.  
  38. /* Win32 Screen buffer,coordinate,console I/O information */
  39. CONSOLE_SCREEN_BUFFER_INFO csbi;
  40. COORD           ntcoord;
  41. INPUT_RECORD    ir;
  42.  
  43. /* The attribute of the screen when the editor was started */
  44. WORD            DefaultAttribute;
  45.  
  46. typedef struct filelist {
  47.     char          **file;
  48.     int             nfiles;
  49.     int             maxfiles;
  50. }               FileList;
  51.  
  52. static void addfile __ARGS((FileList *, char *, int));
  53. static int      pstrcmp();      /* __ARGS((char **, char **)); BCC does not
  54.                                  * like this */
  55. static void strlowcpy __ARGS((char *, char *));
  56. static int expandpath __ARGS((FileList *, char *, int, int, int));
  57.  
  58. static int      cbrk_pressed = FALSE;   /* set by ctrl-break interrupt */
  59. static int      ctrlc_pressed = FALSE;  /* set when ctrl-C or ctrl-break
  60.                                          * detected */
  61.  
  62. void            vim_delay()
  63. {
  64.     delay(500);
  65. }
  66.  
  67. /*
  68.  * this version of remove is not scared by a readonly (backup) file
  69.  */
  70. int             vim_remove(name)
  71.     char           *name;
  72. {
  73.     setperm(name, _S_IWRITE);   /* default permissions */
  74.     return unlink(name);
  75. }
  76.  
  77. /*
  78.  * mch_write(): write the output buffer to the screen
  79.  */
  80. void            mch_write(s, len)
  81.     char           *s;
  82.     int             len;
  83. {
  84.     char           *p;
  85.     int             row,
  86.                     col;
  87.  
  88.     s[len] = '\0';
  89.     if (term_console)           /* translate ESC | sequences into bios calls */
  90.         while (len--) {
  91.  
  92.             /* optimization: use one single WriteConsole for runs of text,
  93.                rather than calling putch() multiple times.  It ain't curses,
  94.                but it helps. */
  95.  
  96.             DWORD           prefix = strcspn(s, "\n\r\a\033");
  97.  
  98.             if (prefix) {
  99.                 DWORD           nwritten;
  100.  
  101.                 if (WriteConsole(hConOut, s, prefix, &nwritten, 0)) {
  102.  
  103.                     len -= (nwritten - 1);
  104.                     s += nwritten;
  105.                 }
  106.                 continue;
  107.             }
  108.  
  109.             if (s[0] == '\n') {
  110.                 if (ntcoord.Y == (Rows - 1)) {
  111.                     gotoxy(1, ntcoord.Y + 1);
  112.                     scroll();
  113.                 } else {
  114.                     gotoxy(1, ntcoord.Y + 2);
  115.                 }
  116.                 s++;
  117.                 continue;
  118.             } else if (s[0] == '\r') {
  119.                 gotoxy(1, ntcoord.Y + 1);
  120.                 s++;
  121.                 continue;
  122.             } else if (s[0] == '\a') {
  123.                 vbell();
  124.                 s++;
  125.                 continue;
  126.             } else if (s[0] == ESC && len > 1 && s[1] == '|') {
  127.                 switch (s[2]) {
  128.  
  129.                 case 'v':
  130.                     cursor_visible(0);
  131.                     goto got3;
  132.  
  133.                 case 'V':
  134.                     cursor_visible(1);
  135.                     goto got3;
  136.  
  137.                 case 'J':
  138.                     clrscr();
  139.                     goto got3;
  140.  
  141.                 case 'K':
  142.                     clreol();
  143.                     goto got3;
  144.  
  145.                 case 'L':
  146.                     insline(1);
  147.                     goto got3;
  148.  
  149.                 case 'M':
  150.                     delline(1);
  151.             got3:   s += 3;
  152.                     len -= 2;
  153.                     continue;
  154.  
  155.                 case '0':
  156.                 case '1':
  157.                 case '2':
  158.                 case '3':
  159.                 case '4':
  160.                 case '5':
  161.                 case '6':
  162.                 case '7':
  163.                 case '8':
  164.                 case '9':
  165.                     p = s + 2;
  166.                     row = getdigits(&p);        /* no check for length! */
  167.                     if (p > s + len)
  168.                         break;
  169.                     if (*p == ';') {
  170.                         ++p;
  171.                         col = getdigits(&p);    /* no check for length! */
  172.                         if (p > s + len)
  173.                             break;
  174.                         if (*p == 'H') {
  175.                             gotoxy(col, row);
  176.                             len -= p - s;
  177.                             s = p + 1;
  178.                             continue;
  179.                         }
  180.                     } else if (*p == 'm') {
  181.                         if (row == 0)
  182.                             normvideo();
  183.                         else
  184.                             textattr(row);
  185.                         len -= p - s;
  186.                         s = p + 1;
  187.                         continue;
  188.                     } else if (*p == 'L') {
  189.                         insline(row);
  190.                         len -= p - s;
  191.                         s = p + 1;
  192.                         continue;
  193.                     } else if (*p == 'M') {
  194.                         delline(row);
  195.                         len -= p - s;
  196.                         s = p + 1;
  197.                         continue;
  198.                     }
  199.                 }
  200.             }
  201.             putch(*s++);
  202.         }
  203.     else
  204.         write(1, s, (unsigned) len);
  205. }
  206. /*
  207.  *  Keyboard translation tables.
  208.  *  (Adopted from the MSDOS port)
  209.  */
  210.  
  211. #define KEYPADLO    0x47
  212. #define KEYPADHI    0x53
  213.  
  214. #define PADKEYS     (KEYPADHI - KEYPADLO + 1)
  215. #define iskeypad(x)    (KEYPADLO <= (x) && (x) <= KEYPADHI)
  216.  
  217. /*
  218.  * Wait until console input is available
  219.  */
  220.  
  221. static int      WaitForChar(msec)
  222.     int             msec;
  223. {
  224.     int             count;
  225.     int             ch;
  226.     int             scan;
  227.     int             shiftstate;
  228.     int             altseq;
  229.     int             retval = 0;
  230.  
  231.     if (WaitForSingleObject(hConIn, msec) == WAIT_OBJECT_0) {
  232.         count = 0;
  233.         PeekConsoleInput(hConIn, &ir, 1, &count);
  234.         if (count > 0) {
  235.             ch = ir.Event.KeyEvent.uChar.AsciiChar;
  236.             scan = ir.Event.KeyEvent.wVirtualScanCode;
  237.             shiftstate = ir.Event.KeyEvent.dwControlKeyState;
  238.             if (((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown) &&
  239.                 (ch || (iskeypad(scan)))) {
  240.                 retval = 1;     /* Found what we sought */
  241.             }
  242.         } else {                /* There are no events in console event queue */
  243.             retval = 0;
  244.         }
  245.     }
  246.     return retval;
  247. }
  248.  
  249. static int pending = 0;
  250.  
  251. int             tgetch()
  252. {
  253.     int             valid = 0;
  254.     int             metaflags = 0;
  255.     int             count;
  256.     unsigned short int scan;
  257.     unsigned char   ch;
  258.     unsigned long   shiftstate;
  259.     const struct pad *kpad;
  260.     char            keymess[100];
  261.  
  262.     if (pending)
  263.     {
  264.         ch = pending;
  265.         pending = 0;
  266.     }
  267.     else
  268.     {
  269.  
  270.         valid = 0;
  271.         while (!valid) {
  272.             ReadConsoleInput(hConIn, &ir, 1, &count);
  273.             if (ir.EventType == WINDOW_BUFFER_SIZE_EVENT) {
  274.                 set_winsize(Rows, Columns, FALSE);
  275.             } 
  276.             else
  277.             {
  278.                 if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown) 
  279.                 {
  280.                     ch = ir.Event.KeyEvent.uChar.AsciiChar;
  281.                     scan = ir.Event.KeyEvent.wVirtualScanCode;
  282.                     if (ch || (iskeypad(scan)))
  283.                         valid = 1;
  284.                 }
  285.             }
  286.         }
  287.         if (!ch)
  288.         {
  289.             pending = scan;
  290.             ch = 0;
  291.         }
  292.     }
  293.     return ch;
  294. }
  295.  
  296.  
  297. int             kbhit()
  298. {
  299.     int             done = 0;   /* true =  "stop searching"        */
  300.     int             retval;     /* true =  "we had a match"        */
  301.     int             count;
  302.     unsigned short int scan;
  303.     unsigned char   ch;
  304.     unsigned long   shiftstate;
  305.  
  306.     if (pending)
  307.         return 1;
  308.  
  309.     done = 0;
  310.     retval = 0;
  311.     while (!done) {
  312.         count = 0;
  313.         PeekConsoleInput(hConIn, &ir, 1, &count);
  314.         if (count > 0) {
  315.             ch = ir.Event.KeyEvent.uChar.AsciiChar;
  316.             scan = ir.Event.KeyEvent.wVirtualScanCode;
  317.             shiftstate = ir.Event.KeyEvent.dwControlKeyState;
  318.             if (((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown) &&
  319.                 (ch || (iskeypad(scan)) )) {
  320.                 done = 1;       /* Stop looking         */
  321.                 retval = 1;     /* Found what we sought */
  322.             } else              /* Discard it, its an insignificant event */
  323.                 ReadConsoleInput(hConIn, &ir, 1, &count);
  324.         } else {                /* There are no events in console event queue */
  325.             done = 1;           /* Stop looking               */
  326.             retval = 0;
  327.         }
  328.     }
  329.     return retval;
  330. }
  331.  
  332.  
  333. /*
  334.  * GetChars(): low level input funcion.
  335.  * Get a characters from the keyboard.
  336.  * If time == 0 do not wait for characters.
  337.  * If time == n wait a short time for characters.
  338.  * If time == -1 wait forever for characters.
  339.  */
  340. int             GetChars(buf, maxlen, time)
  341.     char           *buf;
  342.     int             maxlen;
  343.     int             time;
  344. {
  345.     int             len = 0;
  346.     int             c;
  347.  
  348.     if (time >= 0) {
  349.         if (time == 0)          /* don't know if time == 0 is allowed */
  350.             time = 1;
  351.         if (WaitForChar(time) == 0)     /* no character available */
  352.             return 0;
  353.     } else {                    /* time == -1 */
  354.         /* If there is no character available within 2 seconds (default)
  355.          * write the autoscript file to disk */
  356.         if (WaitForChar((int) p_ut) == 0)
  357.             updatescript(0);
  358.     }
  359.  
  360. /*
  361.  * Try to read as many characters as there are.
  362.  * Works for the controlling tty only.
  363.  */
  364.     --maxlen;                   /* may get two chars at once */
  365.     /* we will get at least one key. Get more if they are available After a
  366.      * ctrl-break we have to read a 0 (!) from the buffer. bioskey(1) will
  367.      * return 0 if no key is available and when a ctrl-break was typed. When
  368.      * ctrl-break is hit, this does not always implies a key hit. */
  369.     cbrk_pressed = FALSE;
  370.     while ((len == 0 || kbhit()) && len < maxlen) {
  371.         switch (c = tgetch()) {
  372.         case 0:
  373.             *buf++ = K_NUL;
  374.             break;
  375.         case 3:
  376.             cbrk_pressed = TRUE;
  377.             /* FALLTHROUGH */
  378.         default:
  379.             *buf++ = c;
  380.         }
  381.         len++;
  382.     }
  383.     return len;
  384. }
  385.  
  386. /*
  387.  * We have no job control, fake it by starting a new shell.
  388.  */
  389. void            mch_suspend()
  390. {
  391.     outstr("new shell started\n");
  392.     call_shell(NULL, 0, TRUE);
  393. }
  394.  
  395. extern int      _fmode;
  396. char            OrigTitle[256];
  397. /*
  398.  */
  399. void            mch_windinit()
  400. {
  401.     CONSOLE_SCREEN_BUFFER_INFO csbi;
  402.  
  403.     _fmode = O_BINARY;          /* we do our own CR-LF translation */
  404.     flushbuf();
  405.  
  406.     /* Obtain handles for the standard Console I/O devices */
  407.     hConIn = CreateFile("CONIN$",
  408.                         GENERIC_READ | GENERIC_WRITE,
  409.                         FILE_SHARE_READ | FILE_SHARE_WRITE,
  410.                         NULL, OPEN_EXISTING, 0, NULL);
  411.  
  412.     hConOut = CreateFile("CONOUT$",
  413.                          GENERIC_READ | GENERIC_WRITE,
  414.                          FILE_SHARE_READ | FILE_SHARE_WRITE,
  415.                          NULL, OPEN_EXISTING, 0, NULL);
  416.  
  417.     GetConsoleTitle(OrigTitle, sizeof(OrigTitle));
  418.  
  419.     /* get current attributes and fill out CHAR_INFO structure for fill char */
  420.     GetConsoleScreenBufferInfo(hConOut, &csbi);
  421.     DefaultAttribute = csbi.wAttributes;
  422.  
  423.     mch_get_winsize();
  424. }
  425.  
  426. void            check_win(argc, argv)
  427.     int             argc;
  428.     char          **argv;
  429. {
  430.     if (!isatty(0) || !isatty(1)) {
  431.         fprintf(stderr, "VIM: no controlling terminal\n");
  432.         exit(2);
  433.     }
  434.     /* In some cases with DOS 6.0 on a NEC notebook there is a 12 seconds
  435.      * delay when starting up that can be avoided by the next two lines.
  436.      * Don't ask me why! This could be fixed by removing setver.sys from
  437.      * config.sys. Forget it. gotoxy(1,1); cputs(" "); */
  438. }
  439.  
  440. /*
  441.  * fname_case(): Set the case of the filename, if it already exists.
  442.  *                 msdos filesystem is far to primitive for that. do nothing.
  443.  */
  444. void            fname_case(name)
  445.     char           *name;
  446. {
  447. }
  448.  
  449.  
  450. /*
  451.  * mch_settitle(): set titlebar of our window
  452.  * Can the icon also be set?
  453.  */
  454. void         mch_settitle(title, icon)
  455.     char           *title;
  456.     char           *icon;
  457. {
  458.     if (title != NULL)
  459.         SetConsoleTitle(title);
  460. }
  461.  
  462. /*
  463.  * Restore the window/icon title.
  464.  * which is one of:
  465.  *    1  Just restore title
  466.  *  2  Just restore icon (which we don't have)
  467.  *    3  Restore title and icon (which we don't have)
  468.  */
  469.     void
  470. mch_restore_title(which)
  471.     int which;
  472. {
  473.     mch_settitle((which & 1) ? OrigTitle : NULL, NULL);
  474. }
  475.  
  476. /*
  477.  * Get name of current directory into buffer 'buf' of length 'len' bytes.
  478.  * Return non-zero for success.
  479.  */
  480. int             vim_dirname(buf, len)
  481.     char           *buf;
  482.     int             len;
  483. {
  484.     return (_getcwd(buf, len) != NULL);
  485. }
  486.  
  487. /*
  488.  * get absolute filename into buffer 'buf' of length 'len' bytes
  489.  */
  490. int             FullName(fname, buf, len)
  491.     char           *fname,
  492.                    *buf;
  493.     int             len;
  494. {
  495.     if (fname == NULL)          /* always fail */
  496.         return FAIL;
  497.  
  498.     if (_fullpath(buf, fname, len) == NULL) {
  499.         strncpy(buf, fname, len);       /* failed, use the relative path name */
  500.         return FAIL;
  501.     }
  502.     return OK;
  503. }
  504.  
  505. /*
  506.  * return TRUE is fname is an absolute path name
  507.  */
  508.     int
  509. isFullName(fname)
  510.     char_u        *fname;
  511. {
  512.     return (STRCHR(fname, ':') != NULL);
  513. }
  514.  
  515. /*
  516.  * get file permissions for 'name'
  517.  * -1 : error
  518.  * else FA_attributes defined in dos.h
  519.  */
  520. long            getperm(name)
  521.     char           *name;
  522. {
  523.     int             r;
  524.     struct stat     sb;
  525.  
  526.     r = _stat(name, &sb);       /* get file mode */
  527.  
  528.     if (r)
  529.         return r;
  530.     else
  531.         return sb.st_mode;
  532. }
  533.  
  534. /*
  535.  * set file permission for 'name' to 'perm'
  536.  */
  537. int             setperm(name, perm)
  538.     char           *name;
  539.     long            perm;
  540. {
  541.     return _chmod(name, (int) perm);
  542. }
  543.  
  544. /*
  545.  * check if "name" is a directory
  546.  */
  547. int             isdir(name)
  548.     char           *name;
  549. {
  550.     int             f;
  551.  
  552.     f = getperm(name);
  553.     if (f == -1)
  554.         return -1;              /* file does not exist at all */
  555.     if ((f & _S_IFDIR) == 0)
  556.         return FAIL;               /* not a directory */
  557.     return OK;
  558. }
  559.  
  560. /*
  561.  * Careful: mch_windexit() may be called before mch_windinit()!
  562.  */
  563. void            mch_windexit(r)
  564.     int             r;
  565. {
  566.     settmode(0);
  567.     stoptermcap();
  568.     flushbuf();
  569.     ml_close_all();                 /* remove all memfiles */
  570.     mch_restore_title(3);
  571.     exit(r);
  572. }
  573.  
  574. /*
  575.  * function for ctrl-break interrupt
  576.  */
  577. BOOL WINAPI     handler_routine(DWORD dwCtrlType)
  578. {
  579.     cbrk_pressed = TRUE;
  580.     ctrlc_pressed = TRUE;
  581. }
  582.  
  583. /*
  584.  * set the tty in (raw) ? "raw" : "cooked" mode
  585.  *
  586.  */
  587.  
  588. void            mch_settmode(raw)
  589.     int             raw;
  590. {
  591.     long            cmodein;
  592.     long            cmodeout;
  593.     long            mask;
  594.  
  595.     GetConsoleMode(hConIn, &cmodein);
  596.     GetConsoleMode(hConOut, &cmodeout);
  597.  
  598.     if (raw) {
  599.         if (term_console)
  600.             outstr(T_TP);       /* set colors */
  601.  
  602.         cmodein &= ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT |
  603.                      ENABLE_ECHO_INPUT);
  604.         cmodein |= ENABLE_WINDOW_INPUT;
  605.  
  606.         SetConsoleMode(hConIn, cmodein);
  607.  
  608.         cmodeout &= ~(ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
  609.         SetConsoleMode(hConOut, cmodeout);
  610.         SetConsoleCtrlHandler(handler_routine, TRUE);
  611.     } else {
  612.  
  613.         if (term_console)
  614.             normvideo();        /* restore screen colors */
  615.  
  616.         cmodein |= (ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT |
  617.                     ENABLE_ECHO_INPUT);
  618.         cmodein &= ~(ENABLE_WINDOW_INPUT);
  619.  
  620.         SetConsoleMode(hConIn, cmodein);
  621.  
  622.         cmodeout |= (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
  623.  
  624.         SetConsoleMode(hConOut, cmodeout);
  625.  
  626.         SetConsoleCtrlHandler(handler_routine, FALSE);
  627.     }
  628. }
  629.  
  630. int             mch_get_winsize()
  631. {
  632.     int             i;
  633. /*
  634.  * Use the console mode API
  635.  */
  636.     if (GetConsoleScreenBufferInfo(hConOut, &csbi)) {
  637.         Rows = csbi.dwSize.Y;
  638.         Columns = csbi.dwSize.X;
  639.         DefaultAttribute = csbi.wAttributes;
  640.     } else {
  641.         Rows = 25;
  642.         Columns = 80;
  643.     }
  644.  
  645.     if (Columns < 5 || Columns > MAX_COLUMNS ||
  646.         Rows < 2 || Rows > MAX_COLUMNS) {
  647.         /* these values are overwritten by termcap size or default */
  648.         Columns = 80;
  649.         Rows = 25;
  650.         return OK;
  651.     }
  652.     /* Rows_max = Rows;            /* remember physical max height */
  653.  
  654.     check_winsize();
  655.     /*script_winsize();*/
  656.  
  657.     return OK;
  658. }
  659.  
  660. /*********************************************************************
  661. * FUNCTION: perr(PCHAR szFileName, int line, PCHAR szApiName,        *
  662. *                DWORD dwError)                                      *
  663. *                                                                    *
  664. * PURPOSE: report API errors. Allocate a new console buffer, display *
  665. *          error number and error text, restore previous console     *
  666. *          buffer                                                    *
  667. *                                                                    *
  668. * INPUT: current source file name, current line number, name of the  *
  669. *        API that failed, and the error number                       *
  670. *                                                                    *
  671. * RETURNS: none                                                      *
  672. *********************************************************************/
  673.  
  674. /* maximum size of the buffer to be returned from FormatMessage */
  675. #define MAX_MSG_BUF_SIZE 512
  676.  
  677. void            perr(PCHAR szFileName, int line, PCHAR szApiName, DWORD dwError)
  678. {
  679.     CHAR            szTemp[1024];
  680.     DWORD           cMsgLen;
  681.     CHAR           *msgBuf;     /* buffer for message text from system */
  682.     int             iButtonPressed;     /* receives button pressed in the
  683.                                          * error box */
  684.  
  685.     /* format our error message */
  686.     sprintf(szTemp, "%s: Error %d from %s on line %d:\n", szFileName,
  687.             dwError, szApiName, line);
  688.     /* get the text description for that error number from the system */
  689.     cMsgLen = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
  690.                          FORMAT_MESSAGE_ALLOCATE_BUFFER | 40, NULL, dwError,
  691.      MAKELANGID(0, SUBLANG_ENGLISH_US), (LPTSTR) & msgBuf, MAX_MSG_BUF_SIZE,
  692.                             NULL);
  693.     if (!cMsgLen)
  694.         sprintf(szTemp + strlen(szTemp), "Unable to obtain error message text! \n"
  695.                 "%s: Error %d from %s on line %d", __FILE__,
  696.                 GetLastError(), "FormatMessage", __LINE__);
  697.     else
  698.         strcat(szTemp, msgBuf);
  699.     strcat(szTemp, "\n\nContinue execution?");
  700.     MessageBeep(MB_ICONEXCLAMATION);
  701.     iButtonPressed = MessageBox(NULL, szTemp, "Console API Error",
  702.                           MB_ICONEXCLAMATION | MB_YESNO | MB_SETFOREGROUND);
  703.     /* free the message buffer returned to us by the system */
  704.     if (cMsgLen)
  705.         LocalFree((HLOCAL) msgBuf);
  706.     if (iButtonPressed == IDNO)
  707.         exit(1);
  708.     return;
  709. }
  710. #define PERR(bSuccess, api) {if (!(bSuccess)) perr(__FILE__, __LINE__, \
  711.     api, GetLastError());}
  712.  
  713.  
  714. void            resizeConBufAndWindow(HANDLE hConsole, SHORT xSize, SHORT ySize)
  715. {
  716.     CONSOLE_SCREEN_BUFFER_INFO csbi;    /* hold current console buffer info */
  717.     BOOL            bSuccess;
  718.     SMALL_RECT      srWindowRect;       /* hold the new console size */
  719.     COORD           coordScreen;
  720.  
  721.     bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);
  722.     PERR(bSuccess, "GetConsoleScreenBufferInfo");
  723.     /* get the largest size we can size the console window to */
  724.     coordScreen = GetLargestConsoleWindowSize(hConsole);
  725.     PERR(coordScreen.X | coordScreen.Y, "GetLargestConsoleWindowSize");
  726.     /* define the new console window size and scroll position */
  727.     srWindowRect.Right = (SHORT) (min(xSize, coordScreen.X) - 1);
  728.     srWindowRect.Bottom = (SHORT) (min(ySize, coordScreen.Y) - 1);
  729.     srWindowRect.Left = srWindowRect.Top = (SHORT) 0;
  730.     /* define the new console buffer size */
  731.     coordScreen.X = xSize;
  732.     coordScreen.Y = ySize;
  733.     /* if the current buffer is larger than what we want, resize the */
  734.     /* console window first, then the buffer */
  735.     if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y > (DWORD) xSize * ySize) {
  736.         bSuccess = SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect);
  737.         PERR(bSuccess, "SetConsoleWindowInfo");
  738.         bSuccess = SetConsoleScreenBufferSize(hConsole, coordScreen);
  739.         PERR(bSuccess, "SetConsoleScreenBufferSize");
  740.     }
  741.     /* if the current buffer is smaller than what we want, resize the */
  742.     /* buffer first, then the console window */
  743.     if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y < (DWORD) xSize * ySize) {
  744.         bSuccess = SetConsoleScreenBufferSize(hConsole, coordScreen);
  745.         PERR(bSuccess, "SetConsoleScreenBufferSize");
  746.         bSuccess = SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect);
  747.         PERR(bSuccess, "SetConsoleWindowInfo");
  748.     }
  749.     /* if the current buffer *is* the size we want, don't do anything! */
  750.     return;
  751. }
  752.  
  753. void            mch_set_winsize()
  754. {
  755.     resizeConBufAndWindow(hConOut, Columns, Rows);
  756. }
  757.  
  758. int             call_shell(cmd, filter, cooked)
  759.     char           *cmd;
  760.     int             filter;     /* if != 0: called by dofilter() */
  761.     int             cooked;
  762. {
  763.     int             x;
  764.     char            newcmd[200];
  765.  
  766.     flushbuf();
  767.  
  768.     if (cooked)
  769.         settmode(0);            /* set to cooked mode */
  770.  
  771.     if (cmd == NULL)
  772.         x = system(p_sh);
  773.     else {                      /* we use "command" to start the shell, slow
  774.                                  * but easy */
  775.         sprintf(newcmd, "%s /c %s", p_sh, cmd);
  776.         x = system(newcmd);
  777.     }
  778.     outchar('\n');
  779.     if (cooked)
  780.         settmode(1);            /* set to raw mode */
  781.  
  782. #ifdef WEBB_COMPLETE
  783.     if (x && !expand_interactively)
  784. #else
  785.     if (x)
  786. #endif
  787.     {
  788.         smsg("%d returned", x);
  789.         outchar('\n');
  790.     }
  791.     resettitle();
  792.     return x;
  793. }
  794.  
  795. #define FL_CHUNK 32
  796.  
  797. static void     addfile(fl, f, isdir)
  798.     FileList       *fl;
  799.     char           *f;
  800.     int             isdir;
  801. {
  802.     char           *p;
  803.  
  804.     if (!fl->file) {
  805.         fl->file = (char **) alloc(sizeof(char *) * FL_CHUNK);
  806.         if (!fl->file)
  807.             return;
  808.         fl->nfiles = 0;
  809.         fl->maxfiles = FL_CHUNK;
  810.     }
  811.     if (fl->nfiles >= fl->maxfiles) {
  812.         char          **t;
  813.         int             i;
  814.  
  815.         t = (char **) lalloc(sizeof(char *) * (fl->maxfiles + FL_CHUNK), TRUE);
  816.         if (!t)
  817.             return;
  818.         for (i = fl->nfiles - 1; i >= 0; i--)
  819.             t[i] = fl->file[i];
  820.         free(fl->file);
  821.         fl->file = t;
  822.         fl->maxfiles += FL_CHUNK;
  823.     }
  824.     p = alloc((unsigned) (strlen(f) + 1 + isdir));
  825.     if (p) {
  826.         strcpy(p, f);
  827.         if (isdir)
  828.             strcat(p, "/");
  829.     }
  830.     fl->file[fl->nfiles++] = p;
  831. }
  832.  
  833. static int      pstrcmp(a, b)
  834.     char          **a,
  835.                   **b;
  836. {
  837.     return (strcmp(*a, *b));
  838. }
  839.  
  840. int             has_wildcard(s)
  841.     char           *s;
  842. {
  843.     if (s)
  844.         for (; *s; ++s)
  845.             if (*s == '?' || *s == '*')
  846.                 return 1;
  847.     return 0;
  848. }
  849.  
  850. static void     strlowcpy(d, s)
  851.     char           *d,
  852.                    *s;
  853. {
  854.     while (*s)
  855.         *d++ = tolower(*s++);
  856.     *d = '\0';
  857. }
  858.  
  859. static int      expandpath(fl, path, fonly, donly, notf)
  860.     FileList       *fl;
  861.     char           *path;
  862.     int             fonly,
  863.                     donly,
  864.                     notf;
  865. {
  866.     char            buf[MAX_PATH];
  867.     char           *p,
  868.                    *s,
  869.                    *e;
  870.     int             lastn,
  871.                     c = 1,
  872.                     r;
  873.     WIN32_FIND_DATA fb;
  874.     HANDLE          hFind;
  875.  
  876.     lastn = fl->nfiles;
  877.  
  878. /*
  879.  * Find the first part in the path name that contains a wildcard.
  880.  * Copy it into buf, including the preceding characters.
  881.  */
  882.     p = buf;
  883.     s = NULL;
  884.     e = NULL;
  885.     while (*path) {
  886.         if (*path == '\\' || *path == ':' || *path == '/') {
  887.             if (e)
  888.                 break;
  889.             else
  890.                 s = p;
  891.         }
  892.         if (*path == '*' || *path == '?')
  893.             e = p;
  894.         *p++ = *path++;
  895.     }
  896.     e = p;
  897.     if (s)
  898.         s++;
  899.     else
  900.         s = buf;
  901.  
  902.     /* now we have one wildcard component between s and e */
  903.     *e = '\0';
  904.     r = 0;
  905.     /* If we are expanding wildcards we try both files and directories */
  906.     if ((hFind = FindFirstFile(buf, &fb)) == INVALID_HANDLE_VALUE) {
  907.         /* not found */
  908.         strcpy(e, path);
  909.         if (notf)
  910.             addfile(fl, buf, FALSE);
  911.         return 1;               /* unexpanded or empty */
  912.     }
  913.     while (c) {
  914.         strlowcpy(s, fb.cFileName);
  915.         if (*s != '.' || (s[1] != '\0' && (s[1] != '.' || s[2] != '\0'))) {
  916.             strcat(buf, path);
  917.             if (!has_wildcard(path))
  918.                 addfile(fl, buf, (isdir(buf) > 0));
  919.             else
  920.                 r |= expandpath(fl, buf, fonly, donly, notf);
  921.         }
  922.         c = FindNextFile(hFind, &fb);
  923.     }
  924.     qsort(fl->file + lastn, fl->nfiles - lastn, sizeof(char *), pstrcmp);
  925.     FindClose(hFind);
  926.     return r;
  927. }
  928.  
  929. /*
  930.  * MSDOS rebuilt of Scott Ballantynes ExpandWildCard for amiga/arp.
  931.  * jw
  932.  */
  933.  
  934. int             ExpandWildCards(num_pat, pat, num_file, file, files_only, list_notfound)
  935.     int             num_pat;
  936.     char          **pat;
  937.     int            *num_file;
  938.     char         ***file;
  939.     int             files_only,
  940.                     list_notfound;
  941. {
  942.     int             i,
  943.                     r = 0;
  944.     FileList        f;
  945.  
  946.     f.file = NULL;
  947.     f.nfiles = 0;
  948.     for (i = 0; i < num_pat; i++) {
  949.         if (!has_wildcard(pat[i]))
  950.             addfile(&f, pat[i], files_only ? FALSE : (isdir(pat[i]) > 0));
  951.         else
  952.             r |= expandpath(&f, pat[i], files_only, 0, list_notfound);
  953.     }
  954.     if (r == 0) {
  955.         *num_file = f.nfiles;
  956.         *file = f.file;
  957.     } else {
  958.         *num_file = 0;
  959.         *file = NULL;
  960.     }
  961.     return (r ? FAIL : OK);
  962. }
  963.  
  964. void            FreeWild(num, file)
  965.     int             num;
  966.     char          **file;
  967. {
  968.     if (file == NULL || num <= 0)
  969.         return;
  970.     while (num--)
  971.         free(file[num]);
  972.     free(file);
  973. }
  974.  
  975. /*
  976.  * The normal chdir() does not change the default drive.
  977.  * This one does.
  978.  */
  979. #undef chdir
  980. int             vim_chdir(path)
  981.     char           *path;
  982. {
  983.     if (path[0] == NUL)         /* just checking... */
  984.         return FAIL;
  985.     if (path[1] == ':') {       /* has a drive name */
  986.         if (_chdrive(toupper(path[0]) - 'A' + 1))
  987.             return -1;          /* invalid drive name */
  988.         path += 2;
  989.     }
  990.     if (*path == NUL)           /* drive name only */
  991.         return OK;
  992.     return _chdir(path);        /* let the normal chdir() do the rest */
  993. }
  994.  
  995. clrscr()
  996. {
  997.     int             count;
  998.  
  999.     ntcoord.X = 0;
  1000.     ntcoord.Y = 0;
  1001.     FillConsoleOutputCharacter(hConOut, ' ', Columns * Rows,
  1002.                                ntcoord, &count);
  1003.     FillConsoleOutputAttribute(hConOut, DefaultAttribute, Rows * Columns,
  1004.                                ntcoord, &count);
  1005. }
  1006.  
  1007. clreol()
  1008. {
  1009.     int             count;
  1010.     FillConsoleOutputCharacter(hConOut, ' ',
  1011.                                Columns - ntcoord.X,
  1012.                                ntcoord, &count);
  1013.     FillConsoleOutputAttribute(hConOut, DefaultAttribute,
  1014.                                Columns - ntcoord.X,
  1015.                                ntcoord, &count);
  1016. }
  1017.  
  1018. insline(int count)
  1019. {
  1020.     SMALL_RECT      source,
  1021.                     clip;
  1022.     COORD           dest;
  1023.     CHAR_INFO       fill;
  1024.  
  1025.     dest.X = 0;
  1026.     dest.Y = ntcoord.Y + count;
  1027.  
  1028.     source.Left = 0;
  1029.     source.Top = ntcoord.Y;
  1030.     source.Right = Columns;
  1031.     source.Bottom = Rows - 1;
  1032.  
  1033.     fill.Char.AsciiChar = ' ';
  1034.     fill.Attributes = DefaultAttribute;
  1035.  
  1036.     ScrollConsoleScreenBuffer(hConOut, &source, (PSMALL_RECT) 0, dest,
  1037.                               &fill);
  1038. }
  1039.  
  1040. delline(int count)
  1041. {
  1042.     SMALL_RECT      source,
  1043.                     clip;
  1044.     COORD           dest;
  1045.     CHAR_INFO       fill;
  1046.  
  1047.     dest.X = 0;
  1048.     dest.Y = ntcoord.Y;
  1049.  
  1050.     source.Left = 0;
  1051.     source.Top = ntcoord.Y + count;
  1052.     source.Right = Columns;
  1053.     source.Bottom = Rows - 1;
  1054.  
  1055.     /* get current attributes and fill out CHAR_INFO structure for fill char */
  1056.     fill.Char.AsciiChar = ' ';
  1057.     fill.Attributes = DefaultAttribute;
  1058.  
  1059.     ScrollConsoleScreenBuffer(hConOut, &source, (PSMALL_RECT) 0, dest,
  1060.                               &fill);
  1061. }
  1062.  
  1063.  
  1064. scroll()
  1065. {
  1066.     SMALL_RECT      source,
  1067.                     clip;
  1068.     COORD           dest;
  1069.     CHAR_INFO       fill;
  1070.  
  1071.     dest.X = 0;
  1072.     dest.Y = 0;
  1073.  
  1074.     source.Left = 0;
  1075.     source.Top = 1;
  1076.     source.Right = Columns;
  1077.     source.Bottom = Rows - 1;
  1078.  
  1079.     /* get current attributes and fill out CHAR_INFO structure for fill char */
  1080.     fill.Char.AsciiChar = ' ';
  1081.     fill.Attributes = DefaultAttribute;
  1082.  
  1083.     ScrollConsoleScreenBuffer(hConOut, &source, (PSMALL_RECT) 0, dest,
  1084.                               &fill);
  1085. }
  1086.  
  1087. gotoxy(x, y)
  1088.     register int    x,
  1089.                     y;
  1090. {
  1091.     ntcoord.X = x - 1;
  1092.     ntcoord.Y = y - 1;
  1093.     SetConsoleCursorPosition(hConOut, ntcoord);
  1094. }
  1095.  
  1096. normvideo()
  1097. {
  1098.     int             count;
  1099.     WORD            attr = DefaultAttribute;
  1100.  
  1101.     SetConsoleTextAttribute(hConOut, attr);
  1102. }
  1103.  
  1104. textattr(int attr)
  1105. {
  1106.     int             count;
  1107.     WORD            attrw = attr;
  1108.  
  1109.     SetConsoleTextAttribute(hConOut, attr);
  1110. }
  1111.  
  1112. putch(char c)
  1113. {
  1114.     int             count;
  1115.  
  1116.     WriteConsole(hConOut, &c, 1, &count, 0);
  1117.     ntcoord.X += count;
  1118. }
  1119.  
  1120. delay(x)
  1121. {
  1122.     Sleep(x);
  1123. }
  1124.  
  1125. sleep(x)
  1126. {
  1127.     Sleep(x * 1000);
  1128. }
  1129.  
  1130. vbell()
  1131. {
  1132.     COORD           origin = {0, 0};
  1133.     WORD            flash = ~DefaultAttribute & 0xff;
  1134.     WORD            off = DefaultAttribute;
  1135.  
  1136.     int             count;
  1137.     LPWORD          oldattrs = alloc(Rows * Columns * sizeof(WORD));
  1138.  
  1139.     ReadConsoleOutputAttribute(hConOut, oldattrs, Rows * Columns, origin,
  1140.                                 &count);
  1141.     FillConsoleOutputAttribute(hConOut, flash, Rows * Columns, origin,
  1142.                                &count);
  1143.     WriteConsoleOutputAttribute(hConOut, oldattrs, Rows * Columns, origin,
  1144.                                 &count);
  1145.     free(oldattrs);
  1146. }
  1147.  
  1148. cursor_visible(int visible)
  1149. {
  1150.     CONSOLE_CURSOR_INFO cci;
  1151.  
  1152.     cci.bVisible = visible ? TRUE : FALSE;
  1153.     cci.dwSize = 100;           /* 100 percent cursor */
  1154.     SetConsoleCursorInfo(hConOut, &cci);
  1155. }
  1156.  
  1157. void            set_window(void)
  1158. {
  1159. }
  1160.  
  1161. /*
  1162.  * check for an "interrupt signal": CTRL-break or CTRL-C
  1163.  */
  1164. void            breakcheck()
  1165. {
  1166.     if (ctrlc_pressed) {
  1167.         ctrlc_pressed = FALSE;
  1168.         got_int = TRUE;
  1169.     }
  1170. }
  1171.  
  1172.     long
  1173. mch_avail_mem(special)
  1174.     int special;
  1175. {
  1176.     return 0x7fffffff;        /* virual memory eh */
  1177. }
  1178.  
  1179. /*
  1180.  * return non-zero if a character is available
  1181.  */
  1182.     int
  1183. mch_char_avail()
  1184. {
  1185.     return WaitForChar(0);
  1186. }
  1187.  
  1188. /*
  1189.  * set screen mode, always fails.
  1190.  */
  1191.     int
  1192. mch_screenmode(arg)
  1193.     char_u     *arg;
  1194. {
  1195.     EMSG("Screen mode setting not supported");
  1196.     return FAIL;
  1197. }
  1198.